import random
import re

from django.contrib.auth.hashers import check_password, make_password

from libs.yzk_jwt import TokenManager
from .models import User, Team, UserToken
from rest_framework import serializers
from rest_framework_jwt.settings import api_settings
from rest_framework_jwt.views import obtain_jwt_token  # 导入token签发认证的入口
from django.db.models import Q
from rest_framework.exceptions import APIException, ValidationError
from django.conf import settings
from django.core.cache import cache
from faker import Faker

jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER


class LoginSerializer(serializers.ModelSerializer):
    username = serializers.CharField(required=False)
    password = serializers.CharField(required=False)
    phone = serializers.CharField(required=False)
    # sex = serializers.CharField(source='get_user_type_display')
    number = [3]

    class Meta:
        model = User
        fields = ['username', 'password', 'phone']

    # def _get_token(self, user):
    #     try:
    #         payload = jwt_payload_handler(user)
    #         token = jwt_encode_handler(payload)
    #         return token
    #     except Exception as e:
    #         raise ValidationError(e)
    def _get_user(self, attrs):
        import re
        username = attrs.get('username')
        try:
            user = User.objects.all().get(phone=username)
        except Exception as e:
            raise APIException('user not exist')
        if re.match(r'^1[3-9][0-9]{9}$', username):
            print(111)
            user = User.objects.filter(phone=username).first()
        else:
            user = User.objects.filter(username=username).first()
        if not user:
            raise APIException(detail='用户名错误')
        password = attrs.get('password')
        if not user.check_password(password):
            # raise APIException(detail='密码错误')
            # if user and not check_password(password,user.password):
            if self.number[0] > 0:
                print('111>>>>>>>>>>>>>>>>')
                output = f'用户名或者密码错误，你还有{self.number[0]}次机会'
                print(self.number[0])
                self.number[0] -= 1
                raise APIException(output)
            else:
                print('222222222222>>>>>>>>>>>>>>')
                User.objects.all().filter(username=username).update(is_active=0)
                raise APIException('你已经输错三次密码，请等待管理员激活！')
        if not user.is_active:
            raise APIException(detail='您已被锁定，不能登录')
        return user

    def _get_token(self, user):
        token = TokenManager.get_token(user)
        return token

    def validate(self, attrs):
        user = self._get_user(attrs)
        # user签发token
        token = self._get_token(user)
        self.context['id'] = user.id
        self.context['token'] = token
        self.context['username'] = user.username
        self.context['icon'] = 'http://127.0.0.1:8000/media/' + str(user.icon)

        user_info = {'name': user.name,
                     'phone': user.phone,
                     'user_id': user.id,
                     'user_type':user.user_type,
                     'user_type_name': user.get_user_type_display(),  # 获取用户类型的中文显示
                     'team_id': user.team.id,
                     'team_name': user.team.name,
                     'icon':self.context['icon']}
        self.context['user_info'] = user_info

        return attrs


##############################登录序列化################################
class CommonLoginSerializer():
    def _get_user(self, attrs):
        raise APIException('这个方法必须要重写')

    def _get_token(self, user):
        payload = jwt_payload_handler(user)
        token = jwt_encode_handler(payload)
        return token

    def validate(self, attrs):
        # 验证用户名密码逻辑----->签发token逻辑
        # username字段可能是用户，手机号，邮箱---->正则匹配----》 换一种方式 使用Q查询
        user = self._get_user(attrs)
        # 签发token
        token = self._get_token(user)
        # 把用户，token放在序列化类context中[上下文]
        # print(user.username)
        # print(111)
        self.context['username'] = user.username
        self.context['icon'] = settings.BACKEND_URL + user.icon.url
        self.context['token'] = token
        return attrs


# class TeamSerializer(serializers.ModelSerializer):
#     class Meta:
#         model = Team
#         fields = '__all__'

class RegisterSerializer(serializers.ModelSerializer):
    # teams = serializers.ListField(write_only=True)
    check_pwd = serializers.CharField()
    sex = serializers.ChoiceField(choices=User.Sex.choices)

    class Meta:
        model = User
        # 只写
        fields = ['username',
                  'password',
                  'check_pwd',
                  "phone",
                  'name',
                  "sex",
                  'email',
                  'team']

    # 第一种管理员情况的校验两次密码是否一样:
    def _get_password(self, attrs):
        print('第三步')
        password = attrs.get('password')
        check_pwd = attrs.get('check_pwd')
        if not password == check_pwd:
            raise APIException('两次密码不一致')
        return True

    def _get_mobile(self, attrs):
        mobile = attrs.get('doctor')['mobile']
        if re.match(r'^1[3-9][0-9]{9}$', str(mobile)):
            return attrs
        else:
            raise APIException('手机号不规范')

    # 全局钩子
    def validate(self, attrs):
        if self._get_password(attrs):
            attrs.pop('check_pwd')
        self.context['username'] = attrs.get('username')
        if not attrs.get('doctor'):
            return attrs
        self._get_mobile(attrs)
        return attrs

    def create(self, validated_data):
        # 校验完成的数据
        print('qqqq', validated_data)
        # 把刚刚注册的用户都设置初始状态为0，加入字段存进数据库
        validated_data['is_active'] = 0
        # teams_data = validated_data.pop('teams')
        password = validated_data.pop('password')
        validated_data['password'] = make_password(password)
        user = User.objects.create(**validated_data)

        # user.team_id.add(*teams_data)

        return user


class ForgetPwdSerializer(serializers.ModelSerializer):
    # 这里的code是用户自己输的
    code = serializers.CharField()
    name = serializers.CharField()
    username = serializers.CharField()
    mobile = serializers.CharField()

    class Meta:
        model = User
        fields = ['username', 'name', 'mobile', 'code']

    def validate(self, attrs):
        username = attrs.get('username')
        name = attrs.get('name')
        mobile = attrs.get('mobile')
        code = attrs.get('code')
        print('attrs', username, name, code, mobile)
        user = User.objects.get(username=username, doctor__name=name, doctor__mobile=mobile)
        # print(username,'>>>>>>')
        # user = User.objects.all().filter(username=username).first()
        print(user, '>>11111>>>')
        # user = User.objects.all().filter(username='zxq').first()
        # user = User.objects.get(doctor__name=name)
        if not user:
            raise APIException('未查到该用户')
        old_code = cache.get('set_code_%s' % mobile)
        print(old_code)
        # old_code = '13140'
        # print(old_code)
        print(code)
        if code == old_code:
            print(1)
            cache.set('set_code_%s' % mobile, '')
            self.context['user'] = user.username
            return attrs
        else:
            raise APIException('验证码不正确')


class LoginUserSerializer(CommonLoginSerializer, serializers.ModelSerializer):
    # 字段自己的规则，username会走唯一性叫校验--->就过不了--->必须要重写该字段
    username = serializers.CharField(required=True)  # 前端没有传参数会报错

    class Meta:
        model = User
        fields = ['username', 'password']  # 只做数据校验---->写校验的字段

    def _get_user(self, attrs):
        username = attrs.get('username')
        password = attrs.get('password')
        user = User.objects.filter(Q(username=username) | Q(mobile=username) | Q(email=username)).first()
        # 登录接口，如果是用默认密码，不允许登录
        if user and user.check_password(password):
            # 说明用户名存在，密码再校验
            print(user)
            return user
        else:
            raise APIException('用户名或者密码错误')


class LoginUserSMSSerializer(CommonLoginSerializer, serializers.Serializer):
    code = serializers.CharField(max_length=4)
    mobile = serializers.CharField()

    def _get_user(self, attrs):
        # attrs 中有手机号码和验证码
        mobile = attrs.get('mobile')
        code = attrs.get('code')

        # 验证验证码是否正确
        old_code = cache.get('send_sms_code_%s' % mobile)
        # 如果是 debug模式，有个万能验证码，这样就不用真正发送短信了
        if code == old_code or (settings.DEBUG or code == '8888'):
            # 验证码正确，查出user
            user = User.objects.filter(mobile=mobile).first()
            if user:
                return user
            else:
                raise APIException('手机号没有注册')
        else:
            raise APIException('验证码错误')


###############################注册序列化############################################
# 注册：1 校验数据  2 保存  3 序列化用不要？存疑（这里有两种情况）
class UserRegisterSerializer(serializers.ModelSerializer):
    code = serializers.CharField(max_length=4, min_length=4, write_only=True)

    class Meta:
        model = User
        fields = ['mobile', 'password', 'code']  # code 不是数据库的字段，需要重写

    # 如果想要限制密码强度，这里可以写个局部钩子

    def _check_code(self, attrs):
        mobile = attrs.get('mobile')
        code = attrs.get('code')
        old_code = cache.get('send_sms_code_%s' % mobile)
        if not (code == old_code or (settings.DEBUG and code == '8888')):
            raise APIException('验证码错误')

    def _pre_save(self, attrs):  # {mobile:122222,code:8888,password:123}
        attrs.pop('code')

        fake = Faker(locale='zh_CN')

        random_name = fake.name()
        attrs['username'] = random_name  # 默认用户名就是手机号  可以随机生成用户名  随机生成有意义的名字（ Faker）

    def validate(self, attrs):
        # 写逻辑
        # 1.检验验证码是否正确
        self._check_code(attrs)
        # 2. 入口前准备 ----> code不是数据库字段，不能入库，username是数据库字段必填，这里没有，写成默认
        self._pre_save(attrs)
        return attrs

    def create(self, validated_data):  # # {mobile:122222,password:123,username:名字}
        # 为什么要重写create？ 因为密码是加密的，如果不写用的models序列化类的，不会给密码加密
        # User.objects.create(**validated_data)  # 密码是明文，必须重写
        user = User.objects.create_user(**validated_data)  # 保存成功，密码就是加密的
        return user


class UserSmsRegisterSerializer(serializers.Serializer):
    mobile = serializers.CharField()
    # password = serializers.CharField()
    code = serializers.CharField(max_length=4, min_length=4, write_only=True)

    def validate(self, attrs):
        # 1.前端传入的手机和验证码先做校验
        mobile = attrs.get('mobile')
        code = attrs.get('code')
        old_code = cache.get('send_sms_mobile%s' % mobile)
        if not (old_code == code or (settings.DEBUG and code == '8888')):
            raise APIException('验证码错误')
        # 2.删除验证码，把手机号码存进数据库，并且随机生成密码重写create方法存入数据库
        attrs.pop('code')
        fake = Faker(locale='zh_CN')

        random_name = fake.name()
        attrs['username'] = random_name  # 默认用户名就是手机号  可以随机生成用户名  随机生成有意义的名字（ Faker）
        password = six_password(6)

        attrs['password'] = password
        # 发送短信通知用户
        # 前端需要把要发送的手机号传入在地址栏中
        # mobile = request.query_params.get('mobile', None)
        # code = get_code()  # 把code存起来，放在缓存中
        # cache.set('send_sms_code_%s' % mobile, code)
        # 从缓存中取
        # cache.get('send_sms_code_%s' % mobile)
        from libs.send_jd_sms import send_sms_by_mobile
        from threading import Thread
        from utils.common_response import APIResponse
        if mobile:
            # 开启一个线程，执行发送短信
            t = Thread(target=send_sms_by_mobile, args=[mobile, password])
            t.start()

        return attrs

    def create(self, validated_data):  # # {mobile:122222,password:123,username:名字}
        # 为什么要重写create？ 因为密码是加密的，如果不写用的models序列化类的，不会给密码加密
        # User.objects.create(**validated_data)  # 密码是明文，必须重写
        user = User.objects.create_user(**validated_data)  # 保存成功，密码就是加密的
        return user


def six_password(count):
    password = ''
    for i in range(count):
        s = random.randint(1, 9)
        password += str(s)
    return password

# class UserUpdatePasswordSerialize(serializers.Serializer):
#     #  前端传入的字段，分析可得出，需要用户名，旧密码和新密码
#     username = serializers.CharField()
#     password = serializers.CharField()
#     old_password = serializers.CharField(write_only=True)
#
#     # 记录三次用户密码修改记录，每次改密码，不能跟之前用过的相同
#     def validated(self,attrs):
#         username = attrs.get('username')
#         password = attrs.get('password')
#         old_password = attrs.get('old_password')
#
#         user = User.objects.filter(username=username).first()
#         if user:
#
#
#         else:
#             raise APIException('手机号没有注册')


class TeamSerializer(serializers.ModelSerializer):
    class Meta:
        model = Team
        fields = '__all__'